package pers.kw.config.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import pers.kw.exceptions.BizException;
import pers.kw.protocol.ExceptionResponse;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 处理全局异常返回JSON RespEntity  借鉴 ResponseEntityExceptionHandler处理
 */
@RestControllerAdvice
public class ResponseExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(ResponseExceptionHandler.class);

    @ExceptionHandler({Exception.class})
    public ExceptionResponse exceptionHandler(Exception e) {
        log.error("全局异常处理", e);
        String resultMsg = "系统内部异常，请联系管理员";
        if (e instanceof BizException) {
            resultMsg = e.getMessage();
        }
        return ExceptionResponse.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), resultMsg);
    }

    @ExceptionHandler({NoHandlerFoundException.class})
    public ExceptionResponse noHandlerFoundException(NoHandlerFoundException e) {
        log.error("全局异常处理", e);
        return ExceptionResponse.fail(HttpStatus.NOT_FOUND.value(), "资源不存在");
    }

    /**
     * 处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常，详情继续往下看代码
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public ExceptionResponse bindExceptionHandler(BindException e) {
        log.error("全局异常处理", e);
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("\n"));
        return ExceptionResponse.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
    }

    /**
     * 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public ExceptionResponse constraintViolationExceptionHandler(ConstraintViolationException e) {
        log.error("全局异常处理", e);
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("\n"));
        return ExceptionResponse.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
    }

    /**
     * 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ExceptionResponse methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        log.error("全局异常处理", e);
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("\n"));
        return ExceptionResponse.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
    }
}
